package com.yayo.mangement.facade.impl;

import com.google.common.collect.Lists;
import com.yayo.mangement.conf.PackageFileConfig;
import com.yayo.mangement.conf.VelocityFactory;
import com.yayo.mangement.facade.GeneraterFacade;
import com.yayo.mangement.info.GeneraterInfo;
import com.yayo.mangement.info.GeneraterRequest;
import com.yayo.mangement.model.GeneraterTableDO;
import com.yayo.mangement.model.Table;
import com.yayo.mangement.model.TableField;
import com.yayo.mangement.paging.Paging;
import com.yayo.mangement.response.Response;
import com.yayo.mangement.service.GeneraterTableService;
import com.yayo.mangement.service.TableFieldService;
import com.yayo.mangement.service.TableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class GeneraterFacadeImpl implements GeneraterFacade {

    @Value("${spring.application.name}")
    private String projectName;

    @Value("${spring.profiles.active}")
    private String active;

    @Autowired
    private TableService tableService;

    @Autowired
    private TableFieldService tableFieldService;

    @Autowired
    private GeneraterTableService generaterTableService;


    @Override
    public Paging<Table> paging(Integer pageNo, Integer pageSize, String tableName) {
        return tableService.paging(pageNo,pageSize,tableName);
    }

    @Override
    public Response<List<TableField>> tableDetail(String tableName) {
        return Response.ok(tableFieldService.tableDetail(tableName));
    }

    @Override
    public Response generater(GeneraterRequest generaterRequest, String userNickName) {
        if(!"dev".equals(active)){
            return Response.fail("not.develop");
        }
        if(StringUtils.isEmpty(generaterRequest.getTableName())){
            return Response.fail("table.name.is.null");
        }
        if(generaterRequest.getLayerList() == null || generaterRequest.getLayerList().isEmpty()){
            return Response.fail("layer.list.is.empty");
        }
        //查询表信息
        Table table = tableService.findByTableName(generaterRequest.getTableName());
        if(table == null){
            return Response.fail("table.name.not.found");
        }
        //查询字段信息
        List<TableField> tableFieldList = tableFieldService.tableDetail(generaterRequest.getTableName());

        //这一步也是为了代码看着清晰一点，感觉没啥太大用性
        GeneraterInfo generaterInfo = this.buildGeneraterInfo(table,tableFieldList,userNickName);

        try {
            //自动生成代码
            this.generateCode(generaterInfo,generaterRequest);
            List<GeneraterTableDO> generaterTableDOList = this.buildGeneraterTableDO(generaterInfo,generaterRequest);
            if(!generaterTableDOList.isEmpty()){
                generaterTableService.creates(generaterTableDOList);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return Response.fail(e.getMessage());
        }

        return Response.ok();
    }

    /**
     * 自动生成
     * @param generaterInfo
     * @throws IOException
     */
    private void generateCode(GeneraterInfo generaterInfo,GeneraterRequest generaterRequest) throws IOException {
        log.info("generate code start,table name :{}", generaterInfo.getTableName());
        VelocityFactory.initVelocityFactory();
        //获取生成文件内各种变量
        VelocityContext context = VelocityFactory.getVelocityContext(generaterInfo);
        //获取生成文件的绝对路径集合，注意：！！项目的所有路径中不能包含中文
        Map<String, String> pathMap = PackageFileConfig.getCodePathList(generaterRequest.getLayerList());
        //后缀名
        for(String key : pathMap.keySet()){
            log.info("generate layer :{}" , key);
            //模版路径
            String template = "template/java/" + key +".vm";
            //xml路径
            if(key.contains("xml")){
                template = "template/xml/" + key + ".vm";
            }
            StringWriter stringWriter = new StringWriter();
            Template tpl = Velocity.getTemplate(template,"UTF-8");
            tpl.merge(context,stringWriter);
            //拼接自动生成文件的地址,绝对路径+文件名+后缀名
            String realPath = pathMap.get(key)+ generaterInfo.getClassName() + key;
            //开始创建文件
            File file = new File(realPath);
            if (!file.exists()) {
                File dir = new File(file.getParent());
                dir.mkdir();
                file.createNewFile();
            } else{
                //为了防止意外，已经存在的文件暂时不进行重写
                continue;
            }
            //写入文件
            OutputStream outputStream = new FileOutputStream(realPath);
            IOUtils.write(stringWriter.toString(),outputStream,"UTF-8");
            IOUtils.close(stringWriter);
            log.info("generate layer end");
        }
        log.info("generater code end");
    }

    /**
     * 构建文件内容变量实体类
     * @param table
     * @param tableFieldList
     * @param userNickName
     * @return
     */
    private GeneraterInfo buildGeneraterInfo(Table table, List<TableField> tableFieldList, String userNickName) {
        //查询主键名称，这里的逻辑可以挪到vm中，但是我觉得那里面写着太乱遭，就放这了
        TableField tf = tableFieldList.stream().filter(tableField -> tableField.isKeyIdentityFlag()).findFirst().orElse(null);
        return GeneraterInfo.builder()
                .createdBy(userNickName)
                .className(table.getClassName())
                .comment(table.getComment())
                .columns(tableFieldList)
                .classVariable(table.getClassVariable())
                .primaryKey(tf.getPropertyName())
                .tableName(table.getTableName())
                .build();
    }


    /**
     * 构建已生成文件的信息实体类
     * @param generaterInfo
     * @param request
     * @return
     */
    private List<GeneraterTableDO> buildGeneraterTableDO(GeneraterInfo generaterInfo,GeneraterRequest request) {
        //查询已有数据
        List<GeneraterTableDO> tableList = generaterTableService.findByTableName(request.getTableName());
        List<GeneraterTableDO> list = Lists.newArrayList();
        for(String layerName : request.getLayerList()){
            //判断是否有重复数据
            GeneraterTableDO sameData = tableList.stream().filter(table -> table.getLayerName().equals(layerName)).findFirst().orElse(null);
            if(sameData == null) {
                GeneraterTableDO generaterTableDO = new GeneraterTableDO();
                generaterTableDO.setLayerName(layerName);
                generaterTableDO.setTableName(request.getTableName());
                generaterTableDO.setCreatedBy(generaterInfo.getCreatedBy());
                list.add(generaterTableDO);;
            }
        }
        return list;
    }


}
